Improve performance of `file-truename' (bug#70036)
authorIhor Radchenko <yantar92@posteo.net>
Tue, 30 Apr 2024 11:27:04 +0000 (14:27 +0300)
committerEli Zaretskii <eliz@gnu.org>
Thu, 2 May 2024 09:39:39 +0000 (12:39 +0300)
* lisp/files.el (file-truename): Avoid repetitive calls to
`file-name-nondirectory'.  These calls contribute
significantly to CPU time.  See the benchmarks in
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=70036#47

lisp/files.el

index 7dec67c5cf05942e5494aee057b5f900309391ba..b7ebb727c72d474732632af3e2113e254d448827 100644 (file)
@@ -1504,27 +1504,28 @@ containing it, until no links are left at any level.
                        (new (file-name-as-directory (file-truename dirfile counter prev-dirs))))
                    (setcar prev-dirs (cons (cons old new) (car prev-dirs)))
                    (setq dir new))))
-           (if (equal ".." (file-name-nondirectory filename))
-               (setq filename
-                     (directory-file-name (file-name-directory (directory-file-name dir)))
-                     done t)
-             (if (equal "." (file-name-nondirectory filename))
-                 (setq filename (directory-file-name dir)
-                       done t)
-               ;; Put it back on the file name.
-               (setq filename (concat dir (file-name-nondirectory filename)))
-               ;; Is the file name the name of a link?
-               (setq target (file-symlink-p filename))
-               (if target
-                   ;; Yes => chase that link, then start all over
-                   ;; since the link may point to a directory name that uses links.
-                   ;; We can't safely use expand-file-name here
-                   ;; since target might look like foo/../bar where foo
-                   ;; is itself a link.  Instead, we handle . and .. above.
-                   (setq filename (files--splice-dirname-file dir target)
-                         done nil)
-                 ;; No, we are done!
-                 (setq done t))))))))
+            (let ((filename-no-dir (file-name-nondirectory filename)))
+             (if (equal ".." filename-no-dir)
+                 (setq filename
+                       (directory-file-name (file-name-directory (directory-file-name dir)))
+                       done t)
+               (if (equal "." filename-no-dir)
+                   (setq filename (directory-file-name dir)
+                         done t)
+                 ;; Put it back on the file name.
+                 (setq filename (concat dir filename-no-dir))
+                 ;; Is the file name the name of a link?
+                 (setq target (file-symlink-p filename))
+                 (if target
+                     ;; Yes => chase that link, then start all over
+                     ;; since the link may point to a directory name that uses links.
+                     ;; We can't safely use expand-file-name here
+                     ;; since target might look like foo/../bar where foo
+                     ;; is itself a link.  Instead, we handle . and .. above.
+                     (setq filename (files--splice-dirname-file dir target)
+                           done nil)
+                   ;; No, we are done!
+                   (setq done t)))))))))
     filename))
 
 (defun file-chase-links (filename &optional limit)